package com.sx.utils;

import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.AlgorithmParameters;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Base64;

public class PasswordUtils {

    public static final byte[] AES_IV_BYTE=new byte[]{117,111,109,122,104,121,77,107,100,84,89,79,78,106,51,76};
    public static final byte[] AES_KEY_BYTE=new byte[]{111,70,85,116,81,69,55,109,109,121,68,121,74,79,84,53,57,110,111,58,86,52,88,50,81,70,99,111,49,67,118,108};


    public static final String AES_KEY=new String(AES_KEY_BYTE);
    public static final String AES_IV=new String(AES_IV_BYTE);

    public static final Charset UTF8=Charset.forName("utf8");

    public static final int AES_MODEL_ENCRYPT=Cipher.ENCRYPT_MODE;
    public static final int AES_MODEL_DECRYPT=Cipher.DECRYPT_MODE;


    private volatile static PasswordUtils instance;
    private PasswordUtils(){
        Security.addProvider(new BouncyCastleProvider());
    }


    public static PasswordUtils getInstance(){
        if(instance==null){
            synchronized (PasswordUtils.class){
                instance=new PasswordUtils();
            }
        }
        return instance;
    }




    public byte[] AES(byte[] data,String key,String iv,int model) throws Exception{
        if(StringUtils.isEmpty(key))new Exception("密钥Key不能空");
        if(key.length()>32) key=key.substring(0,32);
        if(StringUtils.isEmpty(iv))new Exception("vi不能为空");
        if(iv.length()<16)new Exception("iv字符串不能小于16");
        if(iv.length()>16)iv=iv.substring(0,16);
        byte[] keyByte=key.getBytes("utf8");
        byte[] ivByte=iv.getBytes("utf8");

        SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
        parameters.init(new IvParameterSpec(ivByte));
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
        cipher.init(model, spec, parameters);
        return cipher.doFinal(data);
    }





    public byte[] AES(byte[] data,int model) throws Exception {
        return this.AES(data,AES_KEY,AES_IV,model);
    }

    public byte[] aes_encrypt(byte[] data) throws Exception {
        return this.AES(data,AES_MODEL_ENCRYPT);
    }

    /**
     * aes 加密转 hex
     * @param key
     * @param iv
     * @param text
     * @return
     * @throws Exception
     */
    public String aes_encrypt_hex(String key,String iv,String text) throws Exception {
        byte[] b= this.AES(text.getBytes("utf8"),key,iv,AES_MODEL_ENCRYPT);
        return toHex(b);
    }

    /**
     * aes hex 解密
     * @param key
     * @param iv
     * @param text
     * @return
     * @throws Exception
     */
    public String aes_decrypt_hex(String key,String iv,String text)throws Exception{
        byte[] data=  Hex.decode(text);
        byte[] res= this.AES(data,key,iv,AES_MODEL_DECRYPT);
        return new String(res);
    }


    /**
     *  AES 加密 在Base64编码
     *  @Date   2019/8/15 11:50
     *  @Author AdinZ QQ1454269
     *  @param
     *  @return
     **/
    public String aes_encrypt_base64(String data,String key,String iv) throws Exception {
        byte[] bytes= this.AES(data.getBytes("utf8"),key,iv,AES_MODEL_ENCRYPT);
        return Base64.getEncoder().encodeToString(bytes);
    }
    /**
     *  解密
     *  @Date   2019/8/15 12:00
     *  @Author AdinZ QQ1454269
     *  @param
     *  @return
     **/
    public String aes_decrypt_base64(String data,String key,String iv) throws Exception {
        byte[] bytes=Base64.getDecoder().decode(data);
        byte[] result= this.AES(bytes,key,iv,AES_MODEL_DECRYPT);
        return new String(result);
    }



    /**
     * 解密
     * @param data
     * @return
     * @throws Exception
     */
    public byte[] aes_decrypt(byte[] data) throws Exception {
        return this.AES(data,AES_MODEL_DECRYPT);
    }

    /**
     * aes 加密 base64编码
     * @param data
     * @return
     * @throws Exception
     */
    public String aes_encrypt_base64(String data) throws Exception {
        byte[] bytes=this.aes_encrypt(data.getBytes(UTF8));
        return Base64.getEncoder().encodeToString(bytes);
    }

    public String aes_encrypt_base64_url(String data) throws Exception {
        byte[] bytes=this.aes_encrypt(data.getBytes(UTF8));
        return Base64.getUrlEncoder().encodeToString(bytes);
    }




    /**
     * aes 解密 base64编码
     * @param data
     * @return
     * @throws Exception
     */
    public String aes_decrypt_base64(String data) throws Exception {
        byte[] bytes=Base64.getDecoder().decode(data);
        byte[] b=this.aes_decrypt(bytes);
        return new String(b);
    }

    public String aes_decrypt_base64_url(String data) throws Exception {
        byte[] bytes=Base64.getUrlDecoder().decode(data);
        byte[] b=this.aes_decrypt(bytes);
        return new String(b);
    }

    public String md5(String data){
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(data.getBytes(UTF8));
            return toHex(bytes).toLowerCase();
        }
        catch (Exception e) {
            return null;
        }
    }

    public String sha1(String data){
        try {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            byte[] bytes = md.digest(data.getBytes(UTF8));
            return toHex(bytes).toLowerCase();
        }catch (Exception e) {
                return null;
        }
    }


    private String toHex(byte[] bytes) {
        final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
        StringBuilder ret = new StringBuilder(bytes.length * 2);
        for (int i=0; i<bytes.length; i++) {
            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
        }
        return ret.toString();
    }


    public String HmacSHA1(String key, String data) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1");
        mac.init(secret_key);
        byte[] array = mac.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }


    public String HmacSHA256(String key, String data)  throws Exception{
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        mac.init(secret_key);
        byte[] array = mac.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }



    public String sha256(String text) {
        MessageDigest messageDigest;
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(text.getBytes("UTF-8"));
            return toHex(messageDigest.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public String base64_url_encode(String text)  {
        try {
            return Base64.getUrlEncoder().encodeToString(text.getBytes("utf8"));
        }catch (Exception ex){
            return null;
        }
    }

    public String base64_url_decode(String text){
        return new String(Base64.getUrlDecoder().decode(text));
    }




}
